home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / piano.zip / PIANO.CPP < prev    next >
C/C++ Source or Header  |  1992-09-06  |  13KB  |  403 lines

  1. // filename    PIANO.CPP
  2. // author    Robert Upleger
  3. // intent    To simulate a piano keyboard.
  4. //        To use graphics to display a piano keyboard on the screen.
  5. //        To play the proper sound for each corresponding key
  6. //        either from the computer keyboard or from disk.
  7. //        To "light-up" each note that is played.
  8. //
  9. // project    To demonstrate the various features of Turbo C++
  10. //              as described in Lafore.   This program includes the use
  11. //        of inheritence, external files, and virtual functions.
  12. //
  13. // class    CSc 311-31  Ahlborn
  14. // assignment    Programming assignment #4 - Final Project
  15. // due-date    07-31-92
  16. // reference    Robert LaFore (The Waite Group's)
  17. //        "Object-Oriented Programming in Turbo C++"
  18. //        Waite Group Press, 1992 - Chapter 11 & 15
  19. //
  20. // description  The program starts with a display of a piano keyboard.
  21. //        A menu of options appears below the piano.
  22. //        The user is presented with four options:
  23. //
  24. //        OPTION #1
  25. //        This option will display the keys on the computer
  26. //        keyboard necessary to play the piano.
  27. //
  28. //        OPTION #2
  29. //        This option will play an old Motown song:
  30. //        'You really got a hold on me.'
  31. //
  32. //        OPTION #3
  33. //        This option plays the scales, forward then backward.
  34. //
  35. //        OPTION #4
  36. //        This option terminates the program.
  37. //
  38. // restriction    For VGA monitors only.
  39. //
  40.  
  41. #include <graphics.h>        // for initgraph(), etc
  42. #include <stdlib.h>        // for exit()
  43. #include <conio.h>        // for getch()
  44. #include <dos.h>        // for delay(), sound(), etc
  45. #include <fstream.h>        // for cout, etc
  46. #include <ctype.h>        // for toupper()
  47.  
  48. enum keystatus { notpushed, pushed } ;        // keyboard status
  49. keystatus kstatus = notpushed ;            // initialize to notpushed
  50.  
  51. struct Note        // structure for note data stored on disk
  52.     {
  53.     char letter ;    // a letter from the keyboard
  54.     float delay ;    // the sound delay in milliseconds
  55.     };
  56.  
  57. class key        // base class for a key type
  58.     {
  59.     protected:
  60.         int left, top, right, bottom ;    // drwaing coordinates
  61.         int color ;            // key color
  62.         float freq;            // note frequency
  63.     public:
  64.         key( int l, int t, int r,  int b , float f )
  65.             { left=l; top=t; right=r; bottom=b; freq=f; }
  66.         virtual void drawkey() = 0 ;     // pure virtual function
  67.         virtual void makesound ( float del ) = 0 ;
  68.     };
  69.  
  70.  
  71. class Lkey : public key        // piano key with a left nub
  72.     {
  73.     public:
  74.         Lkey( int l, int t, int r, int b, float f ) :
  75.             key( l, t, r,  b, f )  {}
  76.         void drawkey()
  77.             {
  78.             // draw key and fill it with pattern & color
  79.             int intarr[ 12 ] ;
  80.             int* p = intarr ;
  81.             *(p +0)  = left +  8      ;    *(p +1)  = top ;
  82.             *(p +2)  = right      ;    *(p +3)  = top ;
  83.             *(p +4)  = right      ;    *(p +5)  = bottom ;
  84.             *(p +6)  = left     ;    *(p +7)  = bottom ;
  85.             *(p +8)  = left     ;    *(p +9)  = top+64 ;
  86.             *(p+10)  = left + 8     ;    *(p+11)  = top+64 ;
  87.             color = ( ( kstatus ) ? BLUE : WHITE ) ;
  88.             setfillstyle( SOLID_FILL , color ) ;
  89.             fillpoly( 6 , p ) ;
  90.             setcolor( 0 );
  91.             rectangle( left+1, top+1, right-1, bottom-1 );
  92.             }
  93.         void makesound ( float del )
  94.             {
  95.             sound( freq ) ;        // play note
  96.             delay( del ) ;        // delay millliseconds
  97.             nosound() ;        // stop sound
  98.             }
  99.  
  100.     };
  101.  
  102. class Rkey : public key         // piano key with a right nub
  103.     {
  104.     public:
  105.         Rkey( int l, int t, int r, int b, float f ) :
  106.             key( l, t, r,  b, f )  {}
  107.         void drawkey()
  108.             {
  109.             // draw key and fill it with pattern & color
  110.             int intarr[ 12 ] ;
  111.             int* p = intarr ;
  112.             *(p +0)  = left           ;    *(p +1)  = top ;
  113.             *(p +2)  = left +  16  ;    *(p +3)  = top ;
  114.             *(p +4)  = left +  16  ;    *(p +5)  = top+64 ;
  115.             *(p +6)  = right       ;    *(p +7)  = top+64 ;
  116.             *(p +8)  = right       ;    *(p +9)  = bottom ;
  117.             *(p+10)  = left        ;    *(p+11)  = bottom ;
  118.             color = ( ( kstatus ) ? BLUE : WHITE ) ;
  119.             setfillstyle( SOLID_FILL , color ) ;
  120.             fillpoly( 6 , p ) ;
  121.             setcolor( 0 ) ;
  122.             rectangle( left+1, top+1, right-1, bottom-1 );
  123.             }
  124.         void makesound ( float del )
  125.             {
  126.             sound( freq ) ;        // play note
  127.             delay( del ) ;        // delay millliseconds
  128.             nosound() ;        // stop sound
  129.             }
  130.     };
  131.  
  132.  
  133. class Bkey : public key        // the black piano keys
  134.     {
  135.     public:
  136.         Bkey( int l, int t, int r, int b, float f ) :
  137.             key( l, t, r,  b, f )  {}
  138.         void drawkey()
  139.             {
  140.             // draw key and fill it with pattern & color
  141.             int intarr[ 10 ] ;
  142.             int* p = intarr ;
  143.             *(p +0)  =  left     ;    *(p +1)  = top ;
  144.             *(p +2)  =  right     ;    *(p +3)  = top ;
  145.             *(p +4)  =  right     ;    *(p +5)  = bottom ;
  146.             *(p +6)  =  left     ;    *(p +7)  = bottom ;
  147.             *(p +8)  =  left     ;    *(p +9)  = top ;
  148.             color = ( ( kstatus ) ? RED : BLACK ) ;
  149.             setfillstyle( SOLID_FILL, color ) ;
  150.             fillpoly( 5, p ) ;
  151.             setcolor( getmaxcolor() ) ;
  152.             rectangle( left+1, top+1, right-1, bottom-1 ) ;
  153.             }
  154.         void makesound ( float del )
  155.             {
  156.             sound( freq ) ;        // play note
  157.             delay( del ) ;        // delay millliseconds
  158.             nosound() ;        // stop sound
  159.             }
  160.     } ;
  161.  
  162. class Ckey : public key        // piano keys inbetween the black keys
  163.     {
  164.     public:
  165.         Ckey( int l, int t, int r, int b, float f ) :
  166.             key( l, t, r,  b, f )  {}
  167.         void drawkey()
  168.             {
  169.             // draw key and fill it with pattern & color
  170.             int intarr[ 16 ] ;
  171.             int* p = intarr ;
  172.             *(p +0)  = left +   8     ;    *(p +1)  = top ;
  173.             *(p +2)  = left +  16     ;    *(p +3)  = top ;
  174.             *(p +4)  = left +  16     ;    *(p +5)  = top+64 ;
  175.             *(p +6)  = right     ;    *(p +7)  = top+64 ;
  176.             *(p +8)  = right     ;    *(p +9)  = bottom ;
  177.             *(p+10)  = left           ;    *(p+11)  = bottom ;
  178.             *(p+12)  = left       ;       *(p+13)  = top+64 ;
  179.             *(p+14)  = left +   8    ;       *(p+15)  = top+64 ;
  180.             color = ( ( kstatus ) ? BLUE : WHITE ) ;
  181.             setfillstyle( SOLID_FILL , color ) ;
  182.             fillpoly( 8 , p ) ;
  183.             setcolor( 0 ) ;
  184.             rectangle( left+1, top+1, right-1, bottom-1 );
  185.             }
  186.         void makesound ( float del )
  187.             {
  188.             sound( freq ) ;        // play note
  189.             delay( del ) ;        // delay millliseconds
  190.             nosound() ;        // stop sound
  191.             }
  192.     };
  193.  
  194.  
  195.  
  196. int main()
  197.     {
  198.     int gdriver = DETECT ;             // auto detection
  199.     int gmode, errorcode ;            
  200.     initgraph( &gdriver, &gmode, "" );    // initialize graphics
  201.     errorcode = graphresult();              // get error code
  202.     if ( errorcode != 0 )            // an error occurred
  203.         {
  204.         cout << "Graphics error: " << grapherrormsg( errorcode ) ;
  205.         getch() ;
  206.         exit(1) ;    // exit program
  207.         }
  208.  
  209.  
  210.     // initialize piano keys           note          keyboard
  211.     // --------------------------------      ---------   --------
  212.  
  213.     Rkey A(  40, 40,  64, 160, 261.63 ) ;    // c natural     char a
  214.     Bkey W(  56, 40,  72, 104, 277.48 ) ;    // c sharp      char w
  215.     Ckey S(  64, 40,  88, 160, 293.66 ) ;    // d natural    char s
  216.     Bkey E(  80, 40,  96, 104, 311.65 ) ;    // e flat    char e
  217.     Lkey D(  88, 40, 112, 160, 329.63 ) ;    // e natural    char d
  218.     Rkey F( 112, 40, 136, 160, 349.23 ) ;    // f natural    char f
  219.     Bkey T( 128, 40, 144, 104, 370.62 ) ;      // f sharp    char t
  220.     Ckey G( 136, 40, 160, 160, 392.00 ) ;    // g natural    char g
  221.     Bkey Y( 152, 40, 168, 104, 416.00 ) ;    // g sharp    char y
  222.     Ckey H( 160, 40, 184, 160, 440.00 ) ;    // a natural    char h
  223.     Bkey U( 176, 40, 192, 104, 466.94 ) ;    // a sharp    char u
  224.     Lkey J( 184, 40, 208, 160, 493.88 ) ;    // b natural     char j
  225.     Rkey K( 208, 40, 232, 160, 523.25 ) ;    // c natural    char k
  226.     Bkey O( 224, 40, 240, 104, 555.28 ) ;    // c sharp    char o
  227.     Ckey L( 232, 40, 256, 160, 587.32 ) ;    // d natural    char l
  228.  
  229.     // set-up pointers to all the keys
  230.  
  231.     Lkey* Lptr ;     // pointer to a left key
  232.     Bkey* Bptr ;    // pointer to a black key
  233.     Rkey* Rptr ;    // pointer to a right key
  234.     Ckey* Cptr ;    // pointer to a center key
  235.  
  236.     // initialize pointers to corresponding note addresses
  237.     // and put pointers into array 'keyptr'
  238.  
  239.     key* keyptr[ 15 ] = {     Rptr = &A , Bptr = &W , Cptr = &S ,
  240.                 Bptr = &E , Lptr = &D , Rptr = &F ,
  241.                 Bptr = &T , Cptr = &G , Bptr = &Y ,
  242.                 Cptr = &H , Bptr = &U , Lptr = &J ,
  243.                 Rptr = &K , Bptr = &O , Cptr = &L } ;
  244.  
  245.     // draw piano keyboard with virtual function 'drawkey()'
  246.  
  247.     for ( int j=0 ; j<15 ; j++ )
  248.         keyptr[ j ] -> drawkey() ;
  249.  
  250.     // initialize variables and function prototypes
  251.  
  252.     Note note ;            // note structure variable
  253.     fstream file ;            // file from a disk
  254.     char ch  ;            // input character
  255.     int mainmenu() ;             // prototype
  256.     int noteptr( char ) ;        // prototype
  257.     void cleartext() ;        // prototype
  258.     void showkeyboard() ;        // prototype
  259.     void invalidoption() ;        // prototype
  260.     char option ;            // input option
  261.     option = toupper(mainmenu());    // initialize option from menu
  262.  
  263.     
  264.  
  265.     do // the option that the user entered
  266.         {
  267.         cleartext() ;        // clear the option menu
  268.         switch( option )    // decide what option to do
  269.             {
  270.             case 'A': {    // do the piano keyboard
  271.                   showkeyboard() ;  // show keyboard menu
  272.                   do    // keep getting a note
  273.                     {
  274.                     ch = getch() ;
  275.                     // assign the key an array index
  276.                     int i = noteptr( ch ) ;
  277.                     // if valid play the piano note
  278.                     if ( i != 99 )
  279.                         {
  280.                         // change keypushed status
  281.                         kstatus = pushed ;
  282.                         // draw pushed key
  283.                         keyptr[ i ] -> drawkey() ;
  284.                         // play the sound
  285.                         keyptr[ i ] -> makesound(200);
  286.                         // change keypushed ststus
  287.                         kstatus = notpushed ;
  288.                         // draw unpushed key
  289.                         keyptr[ i ] -> drawkey() ;
  290.                         }
  291.                     }
  292.                 while ( ch != 'x' );
  293.                 break;
  294.                 }
  295.             case 'B':    // play one of two songs
  296.             case 'C': {
  297.                   if ( option == 'B' )
  298.                     // play Motown
  299.                     file.open( "SONG.DAT" , ios::in ) ;
  300.                     // else play the scales
  301.                   else     file.open( "SONG1.DAT" , ios::in );
  302.                   file.seekg(0) ; // goto begin of file
  303.                   // read the note structure
  304.                   file.read( (char*)¬e, sizeof( note ) ) ;
  305.                   while ( !file.eof() )
  306.                     { // play the note
  307.                     float del = note.delay;
  308.                     ch =  note.letter ;
  309.                     kstatus = pushed ;
  310.                     int i = noteptr( ch ) ;
  311.                     keyptr[ i ] -> drawkey() ;
  312.                     keyptr[ i ] -> makesound(del) ;
  313.                     kstatus = notpushed ;
  314.                     keyptr[ i ] -> drawkey() ;
  315.                                         file.read( (char*)¬e, sizeof( note ) ) ;
  316.                     }
  317.                   file.close() ; // close the file
  318.                   break;
  319.                   }
  320.             default: {
  321.                  invalidoption();  // invalid option
  322.                  }
  323.             }
  324.         cleartext() ;
  325.         option = mainmenu() ;        // get another option
  326.         option = toupper( option ) ;
  327.         }
  328.     while ( option != 'D' ) ;    // 'D' means quit
  329.  
  330.     cleardevice() ;        // clear the graphics screen
  331.     closegraph();        // shuts down the graphics system
  332.     return(0) ;        // return zero, program ran ok
  333.     }
  334.  
  335.  
  336.  
  337.  
  338. char mainmenu()            // the main menu for user option
  339.     {
  340.     char choice ;
  341.     gotoxy( 1, 1    ) ; cout << "    P I A N O    S I M U L A T I O N " ;
  342.     gotoxy( 1, 2    ) ; cout << " ---------------------------------------- " ;
  343.     gotoxy( 5, 13  ) ; cout << "   A.  This option allows you to play " ;
  344.     gotoxy( 5, 14  ) ; cout << "       the keyboard like a piano.   " ;
  345.     gotoxy( 5, 16  ) ; cout << "   B.  This option will play a song: " ;
  346.     gotoxy( 5, 17  ) ; cout << "       \'You really got a hold on me.\'" ;
  347.     gotoxy( 5, 19 )  ; cout << "   C.  This option will play a scale . " ;
  348.     gotoxy( 5, 21 ) ; cout << "   D.  Quit program " ;
  349.     gotoxy( 5, 24 ) ; cout << "       ENTER OPTION: " ;
  350.     gotoxy( 30, 24) ; choice = getch() ;
  351.     return ( choice ) ;
  352.     }
  353.  
  354. void cleartext()        // clears the mainmenu() text
  355.     {
  356.     for ( int j=13; j<30; j++ )
  357.         {
  358.         gotoxy( 1, j ) ;
  359.         cout << "                           \
  360.                               ";
  361.         }
  362.     }
  363.  
  364. void showkeyboard()    // displays message on how to play the keyboard
  365.     {
  366.     gotoxy(  5, 13 ) ; cout << "   W  E     T  Y  U     O    " ;
  367.     gotoxy(  5, 14 ) ; cout << "  A  S  D  F  G  H  J  K  L  " ;
  368.     gotoxy( 35, 13 ) ; cout << " <- THESE ARE THE BLACK KEYS " ;
  369.     gotoxy( 35, 14 ) ; cout << " <- THESE ARE THE WHITE KEYS " ;
  370.     gotoxy(  5, 18 ) ; cout << " PLAY THESE LETTERS ON THE KEYBOARD " ;
  371.     gotoxy(  5, 20 ) ; cout << " TYPE 'x' TO EXIT. " ;
  372.     }
  373.  
  374.  
  375.  
  376. int noteptr( char c )    // returns an index to a pointer value
  377.     {
  378.     if ( c == 'a' ) return(  0 );
  379.     if ( c == 'w' ) return(  1 );
  380.     if ( c == 's' ) return(  2 );
  381.     if ( c == 'e' ) return(  3 );
  382.     if ( c == 'd' ) return(  4 );
  383.     if ( c == 'f' ) return(  5 );
  384.     if ( c == 't' ) return(  6 );
  385.     if ( c == 'g' ) return(  7 );
  386.     if ( c == 'y' ) return(  8 );
  387.     if ( c == 'h' ) return(  9 );
  388.     if ( c == 'u' ) return( 10 );
  389.     if ( c == 'j' ) return( 11 );
  390.     if ( c == 'k' ) return( 12 );
  391.     if ( c == 'o' ) return( 13 );
  392.     if ( c == 'l' ) return( 14 );
  393.     else return ( 99 ) ;
  394.     }
  395.  
  396. void invalidoption()    // invalid option selected - displays message
  397.     {
  398.     gotoxy( 5, 22 );  cout << "\a\aInvalid option - try again. " ;
  399.     gotoxy( 5, 24 ) ; cout << "Hit any key... " ;
  400.     getch() ;
  401.     gotoxy( 5 , 22 ) ; cout << "                               ";
  402.     gotoxy( 5 , 24 ) ; cout << "                               ";
  403.     }